import { default as Stats } from 'stats.js'
import Trigger from './trigger'
import { getCanvas, getWebGLContext, attribute } from './util'
import { createProgram } from './program'
import DataGUI from './gui';
import { config } from './config'

export default class Engine extends Trigger {
    constructor(scene) {
        super();
        let self = this;
        this.scene = scene;
        this.initStats();
        this.initGUI();
        this.initGL();
        this.render();
        window.onresize = () => {
            this.resize();
        };
        this.resize();
        this.on('all', (v) => {
            console.log(v)
        })
    }

    initGL() {
        // 01. create canvas
        const canvas = this.canvas = getCanvas('canvas');

        // 02. create webgl context
        const gl = this.gl = getWebGLContext(canvas);

        gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);

        // 03. create program
        var vs = `
        precision mediump float;
        attribute float a_pointsize;
        attribute vec3 a_position;
        attribute vec4 a_color;
        varying vec4 v_color;
        void main() {
            gl_PointSize = a_pointsize;
            v_color = a_color;
            gl_Position = vec4(a_position, 1.0);
        }`;

        var fs = `
        precision mediump float;
        varying vec4 v_color;
        void main() {
            gl_FragColor = v_color;
        }`;

        // 04. create program 
        this.program = createProgram(gl, vs, fs);
        gl.program = this.program;
    }

    /**
     * render loop
     */
    render() {
        const scene = this.scene;
        if (scene) {
            if (config.basic.dirty.value) {
                this.stats.begin();
                this.renderList();
                this.stats.end();
            }
        }
        requestAnimationFrame(() => {
            this.render();
        });
    }

    /**
     * 强制刷新一次
     */
    renderForce() {
        const scene = this.scene;
        if (scene) {
            this.stats.begin();
            this.renderList();
            this.stats.end();
        }
    }

    renderList() {
        const gl = this.gl, program = this.program;
        this.clear();
        this.scene.forEach((data) => {
            // 05. attribute
            attribute(gl, new Float32Array(data.vertices), 'a_position', 3, gl.FLOAT, gl.FALSE, 3 * Float32Array.BYTES_PER_ELEMENT, 0);
            attribute(gl, new Float32Array(data.colors), 'a_color', 4, gl.FLOAT, gl.FALSE, 4 * Float32Array.BYTES_PER_ELEMENT, 0);

            var a_pointsize = gl.getAttribLocation(gl.program, 'a_pointsize');
            gl.vertexAttrib1f(a_pointsize, data.pointsize);

            // 04: use program
            gl.useProgram(this.program);

            // 05: draw triangles
            if (data.mode === 'drawElements') {
                // gl.drawElements(gl[config.webgl.drawArrays.mode.value], config.webgl.drawArrays.first.value, config.webgl.drawArrays.count.value);
            } else if (data.mode === 'drawElementsInstance') {

            } else {
                gl.drawArrays(gl[config.webgl.drawArrays.mode.value], config.webgl.drawArrays.first.value, config.webgl.drawArrays.count.value);
            }

            gl.useProgram(null);
        });
    }

    clear() {
        let gl = this.gl;
        // clear color
        gl.clearColor(
            config.webgl.clearColor.value[0] / 255,
            config.webgl.clearColor.value[1] / 255,
            config.webgl.clearColor.value[2] / 255,
            1,
        );
        // clear Depth

        // clear Stencil
        if (config.webgl.clear.clearColor.value) gl.clear(gl.COLOR_BUFFER_BIT);
        if (config.webgl.clear.clearColor.value && config.webgl.clear.clearDepth.value) gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        if (config.webgl.clear.clearColor.value && config.webgl.clear.clearDepth.value && config.webgl.clear.clearStencil.value) gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);

    }

    /**
     * resize
     */
    resize() {
        const { clientWidth, clientHeight } = document.documentElement;
        this.canvas.width = clientWidth;
        this.canvas.height = clientHeight;
        // handle high DPI screen
        // toHighDPI(canvas);
        // set viewport
        this.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);
    }

    /**
     * init gui
     */
    initGUI() {
        this.gui = new DataGUI(this);
        // this.config = config;
        // this.gui = new GUI();;
        // let gui = this.gui;
        // let webgl = gui.addFolder('WebGL API');
        // webgl.addColor(config, 'clearColor').onChange((v) => {
        //     this.fire({
        //         type: 'change.clearColor',
        //         value: v
        //     });
        // });
    }

    /**
     * init status
     */
    initStats() {
        const stats = this.stats = new Stats();
        stats.showPanel(0);
        document.body.appendChild(stats.dom);
    }
}
